package controller.transform;

import javax.vecmath.Point3d;
import javax.vecmath.Vector3d;

import math.Precision;
import math.Spherical;

import component.AbstractComponent;
import component.Ball;
import component.Status;
import component.Tube;
import component.group.ComponentGroup;

public abstract class AlignAngle extends AlignMode {

	protected Tube reference = null;
	protected Ball connectionBall = null;
	
	public AlignAngle(Gui gui, Scene scene, AbstractComponent pivotOrAxis) {
		super(gui, scene, pivotOrAxis);
	}

	@Override
	protected void tubeClicked(Tube tube) {
		if (reference == null) {
			selectReference(tube);
		} else {
			selectTubeToAlign(tube);
		}
	}
	
	private void selectTubeToAlign(Tube tube) {
		if (tube != reference && tube.getConnectedComponents().contains(connectionBall)) {
			alignTube(tube);
		} else {
			gui.setStatusText("This tube is not connected to the same ball as the reference.");
		}
	}

	private void alignTube(Tube tube) {
		ComponentGroup group = this.makeSelection(tube);
		if (group == null) return;
		if (group.contains(reference)) {
			gui.setStatusText("Unable to transform, as tube is connected to reference.");
			return;			
		}
		
		Vector3d referenceVector = getVectorFromTube(reference);
		Vector3d alignVector = getVectorFromTube(tube);
		tryToAlign(group, referenceVector, alignVector);
	}
	
	protected abstract void tryToAlign(ComponentGroup group, Vector3d referenceVector, Vector3d alignVector);
	
	private Vector3d getVectorFromTube(Tube tube) {
		Point3d ballPos = connectionBall.getPos();
		if (tube.getPos().epsilonEquals(ballPos, Precision.ERROR_MARGIN)) {
			return tube.getOrientation().getVector();
		} else {
			Spherical orientation = tube.getOrientation();
			orientation.invert();
			return orientation.getVector();
		}
	}

	private void selectReference(Tube tube) {
		if (this.pivotGroup.isDirectlyConnected(tube)) {
			reference = tube;
			for (AbstractComponent c : tube.getConnectedComponents()) {
				if (c instanceof Ball && pivotGroup.contains(c)) {
					connectionBall = (Ball)c;
				}
			}
			if (connectionBall == null) {
				reference = null;
			} else {
				reference.setStatus(Status.SELECTED, true);
				setDefaultText();
			}
		}
	}

	@Override
	protected void setDefaultText() {
		if (reference == null) {
			gui.setStatusText("Click a tube for reference.");
		} else {
			gui.setStatusText("Click a tube connected to the reference, to form a geometric shape.");
		}

	}
	
	@Override
	public void deselected() {
		super.deselected();
		if (reference != null) {
			reference.setStatus(Status.NORMAL);
			reference = null;
		}
		connectionBall = null;
	}

}
